package com.zgh.opcua.manager;

import com.zgh.opcua.entity.NodeEntity;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.milo.opcua.sdk.client.OpcUaClient;
import org.eclipse.milo.opcua.stack.core.Identifiers;
import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId;
import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger;
import org.eclipse.milo.opcua.stack.core.types.enumerated.BrowseDirection;
import org.eclipse.milo.opcua.stack.core.types.enumerated.BrowseResultMask;
import org.eclipse.milo.opcua.stack.core.types.enumerated.NodeClass;
import org.eclipse.milo.opcua.stack.core.types.structured.BrowseDescription;
import org.eclipse.milo.opcua.stack.core.types.structured.BrowseResult;
import org.eclipse.milo.opcua.stack.core.types.structured.ReferenceDescription;

import java.util.HashSet;
import java.util.Set;

/**
 * @ClassName KepwareNodeManager
 * @Description Kepserver节点管理器
 * @Author Administrator
 * @Date 10:42 2025/11/6
 * @Version 1.0
 */
@Slf4j
public class KepwareNodeManager {
    /**
     * 最大递归深度，避免无限递归
     */
    private int maxDepth = 6;
    /**
     * 用于去重，避免循环引用
     */
    private final Set<NodeId> visited = new HashSet<>();

    private static final KepwareNodeManager INSTANCE = new KepwareNodeManager();

    private KepwareNodeManager() {
    }

    /**
     * 获取单例实例（线程安全）
     */
    public static KepwareNodeManager getInstance() {
        return INSTANCE;
    }


    /**
     * 开始浏览根节点，返回树结构
     *
     * @return NodeTree 根节点
     * @throws Exception
     */
    public NodeEntity browseAllNodes() throws Exception {
        NodeId root = NodeId.parse("ns=0;i=85"); // Objects folder

        // 构造当前节点树
        NodeEntity fNode = new NodeEntity();
        fNode.setIndex(root.getNamespaceIndex().intValue());
        fNode.setIdentifier(root.getIdentifier().toString());
        fNode.setName("Root"); // 根节点可自定义
        fNode.setNodeClassValue(NodeClass.Object.getValue());

        browseNodeRecursive(root, fNode, 0);


        return fNode;
    }

    /**
     * 递归浏览节点
     *
     * @param nodeId 当前节点 NodeId
     * @param depth  当前递归深度
     * @return NodeTree 子树
     * @throws Exception
     */
    private void browseNodeRecursive(NodeId nodeId, NodeEntity fNode, int depth) throws Exception {
        // 已访问或超出深度，直接返回
        if (visited.contains(nodeId)) {
            return;
        }
        visited.add(nodeId);


        OpcUaClient client = OpcUaClientInstance.getInstance().getOpcUaClient();

        // 构造 BrowseDescription 请求，浏览 Object 和 Variable 节点
        BrowseDescription browse = new BrowseDescription(
                nodeId, // 父节点的 NodeId
                BrowseDirection.Forward, // 向下浏览（子节点）
                Identifiers.HierarchicalReferences,  // 使用层次化引用,
                true,
                UInteger.valueOf(NodeClass.Object.getValue() | NodeClass.Variable.getValue()),
                UInteger.valueOf(
                        BrowseResultMask.BrowseName.getValue() |
                                BrowseResultMask.DisplayName.getValue() |
                                BrowseResultMask.NodeClass.getValue() |
                                BrowseResultMask.TypeDefinition.getValue()
                )
        );
        // 发送浏览请求
        BrowseResult result = client.browse(browse).get();
        ReferenceDescription[] refs = result.getReferences();

        if (refs == null || refs.length == 0) {
            return;
        }

        for (ReferenceDescription ref : refs) {
            // 转换到 NodeId
            NodeId childId = ref.getNodeId().local().orElse(null);

            if (childId == null) {
                continue;
            }

            // 构造子节点
            NodeEntity childNode = new NodeEntity();
            childNode.setIndex(childId.getNamespaceIndex().intValue());
            childNode.setIdentifier(childId.getIdentifier().toString());
            childNode.setName(ref.getBrowseName().getName());
            childNode.setNodeClassValue(ref.getNodeClass().getValue());
            // 如果是 Object，递归浏览子节点，作为树枝
            if (ref.getNodeClass().getValue() == NodeClass.Object.getValue()) {
                browseNodeRecursive(childId, childNode, depth + 1);
                //只要有叶子节点的树
                if (childNode.getChildren().size() != 0) {
                    fNode.getChildren().add(childNode);
                }

            } else if (ref.getNodeClass().getValue() == NodeClass.Variable.getValue()) {
                // Variable 节点直接作为叶子
                fNode.getChildren().add(childNode);
            } else {
                return;
            }
        }
    }


    public int getMaxDepth() {
        return maxDepth;
    }

    public void setMaxDepth(int maxDepth) {
        this.maxDepth = maxDepth;
    }

    public static void main(String[] args) throws Exception {
        // 创建 OpcUaClient（连接）
        OpcUaClient client = OpcUaClientInstance.getInstance().getOpcUaClient("opc.tcp://192.168.40.103:49320", "None", null, null);
        client.connect().get();

        KepwareNodeManager collector = new KepwareNodeManager();
        collector.setMaxDepth(6);
        NodeEntity nodeEntity = collector.browseAllNodes();
        client.disconnect().get();

    }

}
